package com.alex.statistics.method.clusterAnalysis;


import com.alex.statistics.pojo.request.clusterAnalysis.DensityClusteringRequest;
import com.alex.statistics.pojo.result.clusterAnalysis.DensityClusteringResult;
import org.springframework.stereotype.Service;

import java.util.*;

@Service
public class DensityClusteringService {

    public DensityClusteringResult cluster(DensityClusteringRequest request) {
        long startTime = System.currentTimeMillis();

        // 参数校验
        validateRequest(request);

        // 数据准备
        List<double[]> data = request.getData();
        double eps = request.getEps();
        int minPoints = request.getMinPoints();

        // 初始化结果
        List<Integer> labels = new ArrayList<>(Collections.nCopies(data.size(), -1)); // -1表示未分类
        int clusterId = 0;

        // DBSCAN算法核心逻辑
        for (int i = 0; i < data.size(); i++) {
            if (labels.get(i) != -1) {
                continue; // 已分类
            }

            List<Integer> neighbors = getNeighbors(data, i, eps);

            if (neighbors.size() < minPoints) {
                labels.set(i, -2); // 标记为噪声点
                continue;
            }

            // 创建新簇
            labels.set(i, clusterId);

            // 扩展簇
            Queue<Integer> seeds = new LinkedList<>(neighbors);
            while (!seeds.isEmpty()) {
                int j = seeds.poll();

                if (labels.get(j) == -2) {
                    labels.set(j, clusterId); // 将噪声点重新分类到当前簇
                }

                if (labels.get(j) != -1) {
                    continue; // 已分类
                }

                labels.set(j, clusterId);

                List<Integer> neighborsJ = getNeighbors(data, j, eps);
                if (neighborsJ.size() >= minPoints) {
                    seeds.addAll(neighborsJ);
                }
            }

            clusterId++;
        }

        // 构建结果
        DensityClusteringResult result = new DensityClusteringResult();
        result.setClusterLabels(labels);
        result.setClusterCount(clusterId);
        result.setNoiseCount((int) labels.stream().filter(l -> l == -2).count());
        result.setComputeTime(System.currentTimeMillis() - startTime);

        return result;
    }

    private List<Integer> getNeighbors(List<double[]> data, int index, double eps) {
        List<Integer> neighbors = new ArrayList<>();
        double[] p = data.get(index);

        for (int i = 0; i < data.size(); i++) {
            if (i == index) {
                continue;
            }

            double distance = euclideanDistance(p, data.get(i));
            if (distance <= eps) {
                neighbors.add(i);
            }
        }

        return neighbors;
    }

    private double euclideanDistance(double[] p1, double[] p2) {
        double sum = 0.0;
        for (int i = 0; i < p1.length; i++) {
            sum += Math.pow(p1[i] - p2[i], 2);
        }
        return Math.sqrt(sum);
    }

    private void validateRequest(DensityClusteringRequest request) {
        if (request.getData() == null || request.getData().isEmpty()) {
            throw new IllegalArgumentException("数据不能为空");
        }
        if (request.getEps() <= 0) {
            throw new IllegalArgumentException("邻域半径eps必须大于0");
        }
        if (request.getMinPoints() <= 0) {
            throw new IllegalArgumentException("最小点数minPoints必须大于0");
        }
    }
}    